home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CreatingGames / GameCreators / Inform / examples / Toyshop.inf < prev   
Encoding:
Text File  |  1997-03-15  |  35.7 KB  |  943 lines

  1. ! ----------------------------------------------------------------------------
  2. !  Toyshop 961111                   One of the standard Inform 6 example games
  3. !
  4. !  This is not a real game.  The main example game for Inform is "Advent",
  5. !  a port of Colossal Cave.  Since that's something of an antique, and most
  6. !  of the objects in it are rather simple, this is a collection of more
  7. !  exotic features and peculiar objects.  Note that "Advent" has plenty of
  8. !  interesting doors, a good lantern and bottled oil and water, so those
  9. !  won't be part of the Toyshop.
  10. !
  11. !  Needs Inform 6 with library 6/1 or later to compile.
  12. !
  13. !  To win, simply find 6 interesting things to do and leave by the main exit!
  14. !
  15. !       Object            Is an example of...
  16. !
  17. !  >SA  satchel           Container into which the game silently puts things
  18. !  >HE  helium balloon    Something moving under the control of a daemon
  19. !  >CA  little red car    Vehicle, and pushable from place to place
  20. !  >PF  padded floor      Scenery present in several rooms at once
  21. !  >GR  hand grenade      Timed events: a grenade and its pin
  22. !  >MA  matchbook         Simple fire and matches; changing inventory styles
  23. !  >WC  white candles     A stock of objects identical to each other
  24. !  >GL  white gloves      Two independent objects which can behave as a pair
  25. !  >CO  green cone        Easy before and after rules
  26. !  >HW  high window       Starting and stopping daemons
  27. !  >BC  bolted cupboard   A typical locked container (with key)
  28. !  >GB  glass box         Container light can get through
  29. !  >SB  steel box         Container light can't get through
  30. !  >BL  building blocks   A complicated class definition; piles of objects
  31. !  >CH  Christopher       Someone you can talk to, and persuade to do things
  32. !  >OF  Office            Rules about moving in a particular direction
  33. !  >TB  toothed bag       A container with ideas about what it will allow
  34. !  >SL  spirit level      Something to put on top of things
  35. !  >BB  blackboard        A blackboard to write messages on
  36. !
  37. !  (The code is marked with >SA and so on for easy access with a text editor)
  38. ! ----------------------------------------------------------------------------
  39. Constant DEBUG;
  40. Constant Story "TOYSHOP";
  41. Constant Headline "^An Interactive Demonstration^
  42.              Copyright (c) 1994 by Graham Nelson. All rights given away.^";
  43. Release 4;
  44. Serial "961111";   !   This sets the serial date to the date of this source
  45.                    !   file, not to the date of compilation.
  46.  
  47. !   Now we serve notice to Inform that we do not wish to use the standard
  48. !   routine for the Burn action, and will instead be defining our own:
  49.  
  50. Replace BurnSub;
  51.  
  52. !   Next include the first of the three standard library files:
  53.  
  54. Include "Parser";
  55.  
  56. ! ----------------------------------------------------------------------------
  57. ! >SA  Ungenerously, the player can only carry at most 4 things, but there's
  58. !      a satchel to carry other things around in...
  59. ! ----------------------------------------------------------------------------
  60.  
  61. Constant MAX_CARRIED = 4;
  62. Constant SACK_OBJECT = satchel;
  63.  
  64. Object satchel "satchel"
  65.   with description "Big and with a smile painted on it.",
  66.        name "satchel", article "your",
  67.        when_closed "Your satchel lies on the floor.",
  68.        when_open "Your satchel lies open on the floor.",
  69.   has  container open openable;
  70.  
  71. !   We're going to use the most elaborate scoring system the
  72. !   library provides (even though we're going to make the six tasks all
  73. !   score only 1 point each), so we define all this...
  74.  
  75. Constant TASKS_PROVIDED;
  76. Constant NUMBER_TASKS = 6;
  77. Array    task_scores  -> 1 1 1 1 1 1;
  78. Constant MAX_SCORE = 6;
  79.  
  80. !   And include the library of standard verbs and actions.
  81.  
  82. Include "VerbLib";
  83.  
  84. ! ----------------------------------------------------------------------------
  85. !   Off we go into the Toyshop...
  86. ! ----------------------------------------------------------------------------
  87.  
  88. Class Toyroom
  89.   has  light;
  90.  
  91. Toyroom Toyshop "Toyshop"
  92.   with description
  93.           "The centre of a long east-west hall. Shelves are lined 
  94.            with toys, painted clowns face you from the walls and 
  95.            the floor is lightly padded with colourful mats. A doorway 
  96.            leads north, with a red warning triangle above it.",
  97.        name "clowns" "painted" "shelves" "triangle",
  98.        e_to East_End, w_to West_End, n_to Danger_Zone;
  99.  
  100. Object -> chair "high chair"
  101.   with name "chair" "high"
  102.   has  supporter enterable;
  103.  
  104. ! ----------------------------------------------------------------------------
  105. ! >HE  The balloon is completely self-contained as a piece of code, except
  106. !      that it does not set itself going (though even this could have been
  107. !      arranged): it is set going in the Initialise() routine.
  108. !
  109. !   Notice that the "after" for Drop takes away the "moved" attribute.
  110. !   This is one way to ensure that the "initial" message will always be
  111. !   the one displayed.  (Alternatively, we could have given it a "describe"
  112. !   property.)
  113. ! ----------------------------------------------------------------------------
  114.  
  115. Object -> balloon "helium balloon"
  116.   with description "Blue, with a yellow smile.",
  117.        name "helium" "balloon" "blue" "string",
  118.        initial "A balloon nestles on the ceiling, its long string hanging.",
  119.        before
  120.        [; Attack: remove self; StopDaemon(self);
  121.                 "Easily, you burst the balloon. Pop!^^
  122.                  Shame it was irreplaceable, really.";
  123.        ],
  124.        after
  125.        [; Take: "You take the balloon by its string. It's buoyant!";
  126.           Drop: give balloon ~moved;
  127.                 "The balloon rises gracefully to the ceiling.";
  128.        ],
  129.        daemon
  130.        [ from_room to_room;
  131.           if (random(3)~=1) rfalse;
  132.           from_room=parent(self);
  133.           if (from_room==East_End or West_End) to_room=Toyshop;
  134.           if (from_room==Toyshop)
  135.           {   if (random(2)==1) to_room=East_End;
  136.               else to_room=West_End;
  137.           }
  138.           if (to_room==0) rfalse;
  139.           move self to to_room;
  140.           if (location==from_room)
  141.             "^A breeze blows the balloon away to the ", (name) to_room, ".";
  142.           if (location==to_room)
  143.             "^A breeze blows the balloon in from the ", (name) from_room, ".";
  144.        ];
  145.  
  146. ! ----------------------------------------------------------------------------
  147. ! >CA  There are two exceptions to the ordinary before/after rules, for
  148. !      vehicles and things which can be pushed from place to place: this car
  149. !      demonstrates both at once.
  150. !
  151. !   The "before" for PushDir (push in a named direction) must call
  152. !   AllowPushDir and then return true to signify that the push is legal.
  153. !
  154. !   The "before" for Go must return true to signify that travelling in
  155. !   the object is legal.  (Note that it must also be enterable.)
  156. ! ----------------------------------------------------------------------------
  157.  
  158. Object -> car "little red car"
  159.   with name "little" "red" "car" "kar1",
  160.        description "Large enough to sit inside. Among the controls is a 
  161.                  prominent on/off switch. The numberplate is KAR 1.",
  162.        when_on  "The red car sits here, its engine still running.",
  163.        when_off "A little red car is parked here.",
  164.        before
  165.        [; PushDir: AllowPushDir(); rtrue;
  166.           Go: if (car has on) { Achieved(1); "Brmm!  Brmm!"; }
  167.               print "(The ignition is off at the moment.)^";
  168.        ],
  169.        after
  170.        [; PushDir: "The car rolls very slowly as you push it.";
  171.        ],
  172.   has  switchable enterable static container open;
  173.  
  174. Object -> -> "small note"
  175.   with name "small" "note",
  176.        description
  177.            "  !!!! FROBOZZ MAGIC CAR COMPANY !!!!^
  178.            ^Hello, Driver!^
  179.            ^Instructions for use:^
  180.            ^Switch on the ignition and off you go!^
  181.            ^Warranty:^
  182.            ^This car is guaranteed against all defects for a period of 
  183.             76 milliseconds from date of purchase or until used, 
  184.             whichever comes first.^
  185.            ^Good Luck!";
  186.  
  187. ! ----------------------------------------------------------------------------
  188. ! >PF  An example of an object spread across several (three) rooms:
  189. ! ----------------------------------------------------------------------------
  190.  
  191. Object padded_floor "padded floor"
  192.   with name "padded" "floor" "mats" "padding",
  193.        description "To protect little children and adventurers.",
  194.        before
  195.        [; Take: "It is protected from little children and adventurers.";
  196.        ],
  197.        found_in East_End Toyshop West_End
  198.   has  scenery;
  199.  
  200. ! ----------------------------------------------------------------------------
  201.  
  202. Toyroom Danger_Zone "Danger Zone"
  203.   with description
  204.           "This is the Danger Zone, which you should know better 
  205.            than to go into. A single door leads back south.",
  206.        s_to Toyshop;
  207.  
  208. ! ----------------------------------------------------------------------------
  209. ! >GR  A classic example of a timer (or, as some people call them and
  210. !      appropriately so in this case, a fuse).  To demonstrate stopping
  211. !      a timer before the alarm (and for fun), there is also a pin:
  212. ! ----------------------------------------------------------------------------
  213.  
  214. Object -> grenade "nasty-looking hand grenade"
  215.   with name "hand" "grenade" "nasty" "nasty-looking",
  216.        initial "A nasty-looking hand grenade (there is no other kind) 
  217.                 rolls about irresponsibly on the floor.",
  218.        description "Not recommended for children under 90.",
  219.        before
  220.        [; Pull: if (self has general) "Too late for that.";
  221.               StartTimer(self, 5); give self general;
  222.               move the_pin to player;
  223.               "You pull the pin out, an irrevocable act.";
  224.        ],
  225.        time_left 0,
  226.        time_out
  227.        [;  deadflag=1;
  228.            "^An immense explosion suddenly demolishes the toyshop!^^
  229.              Will you never learn?";
  230.        ],
  231.   has  transparent;
  232.  
  233. Object -> -> the_pin "pin"
  234.   with name "pin",
  235.        description "The pin is designed to be easy to pull.",
  236.        before
  237.        [; Take, Pull: if (self in grenade) <<Pull grenade>>;
  238.           Insert:
  239.               if (self notin grenade && second==grenade)
  240.               {   StopTimer(grenade); move self to grenade;
  241.                   give grenade ~general;
  242.                   "Amazing!  You got the pin back into the grenade!";
  243.               }
  244.        ];
  245.  
  246. ! ----------------------------------------------------------------------------
  247. ! >MA  This is a matchbook of five matches, which is quite simple in that you
  248. !      can only actually have one match at a time: otherwise, it's quite
  249. !      a full implementation.  Note that the inventory lines for the match
  250. !      and the matchbook are coded here.  Note also that the "match" object
  251. !      returns to the book even when the book is empty, so that the parser
  252. !      will still understand requests for matches - which the "before" rule,
  253. !      which automatically removes matches when needed, can then turn down.
  254. !
  255. !      The matchbook has a daemon whose job is to tidy up lost matches.  One
  256. !      might expect this rule to be coded with an "after" routine, to trap
  257. !      the player dropping matches.  But suppose there were a magpie in the
  258. !      game, and it flew down and stole the match but left the matchbook!
  259. !      As it happens there isn't, but this is better form.
  260. ! ----------------------------------------------------------------------------
  261.  
  262. Object -> matchbook "matchbook"
  263.   with name "matchbook" "book" "matches",
  264.        number 5,
  265.        before
  266.        [; Burn: if (match has light)
  267.                 {   remove match; remove matchbook;
  268.                     "What a waste of matches!";
  269.                 }
  270.        ],
  271.        invent
  272.        [;  if (inventory_stage==2)
  273.            {   switch(self.number)
  274.                {   0: print " (empty)";
  275.                    1: print " (1 match left)";
  276.                    default: print " (", self.number, " matches left)";
  277.                }
  278.            }
  279.        ],
  280.        description
  281.        [;  print "The cover advertisement reads 
  282.                   ~Curses - Adventure of a Lunchtime~. The book ";
  283.            switch(self.number)
  284.            {   0: "is empty.";
  285.                1: "has a single match left.";
  286.                default:
  287.                    print_ret "contains ", self.number, " matches.";
  288.            }
  289.        ],
  290.        daemon
  291.        [;   if (match notin matchbook && match notin player)
  292.             {   move match to matchbook;
  293.                 if (match has light)
  294.                 {   give match ~light; StopTimer(match); }
  295.                 StopDaemon(self);
  296.             }
  297.        ],
  298.   has  transparent;
  299.  
  300. Object -> -> match "match"
  301.   with parse_name
  302.        [ i j;   if (self has light) j='burning'; else j='unlit';
  303.                 while (NextWord()=='match' or j) i++;
  304.                 return i;
  305.        ],
  306.        article "an",
  307.        before
  308.        [ i; if (self in matchbook)
  309.             {   i=matchbook.number;
  310.                 if (i==0) "There are no matches left in the book.";
  311.                 i--; matchbook.number=i;
  312.                 move self to player; StartDaemon(matchbook);
  313.                 print "(taking a match from the book, which ";
  314.                 if (i==0) print "is now empty)^";
  315.                 if (i==1) print "has one more left)^";
  316.                 if (i>1)  print "has ", i, " left)^";
  317.                 self.article = "an";
  318.             }
  319.             Take, Remove: if (self in player) "Done.";
  320.             Burn:
  321.                 if (self has light) "The match is already alight.";
  322.                 if (matchbook notin player)
  323.                    "You need the matchbook to strike the match.";
  324.                 give self light; StartTimer(self, 2+random(3));
  325.                 self.article = "a";
  326.                 "You strike the match.";
  327.        ],
  328.        short_name
  329.        [;   if (self has light) print "burning match";
  330.                            else print "unlit match";
  331.             rtrue;
  332.        ],
  333.  
  334.        time_left,
  335.        time_out
  336.        [;   move self to matchbook; give self ~light;
  337.             "^You drop the match as the flame reaches your finger.";
  338.        ];
  339.  
  340. ! ----------------------------------------------------------------------------
  341. ! >WC  A box of eight candles.
  342. !
  343. !      This is a simple way to code up duplicate objects.  For one thing,
  344. !      > take candles
  345. !      does not quite behave as we would hope: it'll only pick up one candle
  346. !      (though "> take four candles" will work).  See the "Block" class
  347. !      below for a way to make good.
  348. !
  349. !      If we had needed a much greater number of candles, we could have used
  350. !      object creation and destruction during play.  See the "Ticket" class
  351. !      from the "Balances" example game.
  352. ! ----------------------------------------------------------------------------
  353.  
  354. Class  Candle
  355.   with name "wax" "candle" "candles",
  356.        short_name "wax candle", plural "wax candles",
  357.        description "It looks just like all the other candles.",
  358.        before
  359.        [; Burn: "Disappointingly, the wick refuses to burn."; ];
  360.  
  361. Object -> "grey tin box"
  362.   with name "tin" "box" "grey",
  363.        description
  364.            "A grey tin box of ~Major's Candles~.",
  365.   has  container openable;
  366.  
  367. Candle -> ->;
  368. Candle -> ->;
  369. Candle -> ->;
  370. Candle -> ->;
  371. Candle -> ->;
  372. Candle -> ->;
  373. Candle -> ->;
  374. Candle -> ->;
  375.  
  376. Toyroom East_End "East End"
  377.   with name "dolls" "nurses",
  378.        description
  379.           "The eastern end of the toyshop is pink, and dolls and 
  380.            nurses line the shelves right up to the high window. 
  381.            A dark doorway leads to a northern side chamber.",
  382.        w_to Toyshop, n_to DarkRoom;
  383.  
  384. ! ----------------------------------------------------------------------------
  385. ! >GL  The following example, suggested to the author by Richard Tucker,
  386. !      demonstrates an apparently tricky case of objects with associated
  387. !   sub-objects.  The pair of white gloves behaves just like any other item
  388. !   of clothing - but the player can also use the left and right gloves
  389. !   independently, can take away or wear only one and so on.  When they
  390. !   come back together (even in a cupboard, say, or on a mantelpiece)
  391. !   they are called a pair again.
  392. !
  393. !   We can do this with only three objects, one daemon and one rule.
  394. !   
  395. !   When the gloves are together, and the player refers to an individual
  396. !   glove, the before rule splits up the pair and starts the daemon.
  397. !   Once active, the daemon tries every turn to re-join them into a pair.
  398. !   (If it succeeds, it turns itself off.)
  399. !
  400. !   Note that the "pair of gloves" object has the "general" attribute exactly
  401. !   when the gloves are apart.  Otherwise the pair-object contains both
  402. !   glove objects, and has "transparent" so that the parser knows the player
  403. !   can see and refer to them.
  404. ! ----------------------------------------------------------------------------
  405.  
  406. Object -> gloves "white gloves"
  407.   with article "a pair of",
  408.        name "white" "gloves" "pair" "of",
  409.        daemon
  410.        [;  if (parent(right_glove) ~= parent(left_glove)) return;
  411.            if ((left_glove has worn && right_glove hasnt worn)
  412.                || (left_glove hasnt worn && right_glove has worn)) return;
  413.            if (left_glove has worn) give gloves worn; else give gloves ~worn;
  414.            move gloves to parent(right_glove); give gloves ~general;
  415.  
  416.            move right_glove to gloves; move left_glove to gloves;
  417.            give right_glove ~worn;     give left_glove ~worn;
  418.            
  419.            StopDaemon(self);
  420.        ],
  421.   has  clothing transparent;
  422.  
  423. Class  Glove
  424.   with article "the",
  425.        name "white" "glove",
  426.        before
  427.        [;  if (self notin gloves) rfalse;
  428.            move left_glove to parent(gloves); move right_glove to parent(gloves);
  429.            if (gloves has worn)
  430.            {   give left_glove worn; give right_glove worn;
  431.            }
  432.            give gloves general; remove gloves;
  433.            StartDaemon(gloves);
  434.        ],
  435.   has  clothing;
  436.  
  437. Glove -> -> left_glove "left glove"
  438.   with description "White silk, monogrammed with a scarlet R.",
  439.        name "left";
  440. Glove -> -> right_glove "right glove"
  441.   with description "White silk, monogrammed with a scarlet T.",
  442.        name "right";
  443.  
  444. ! ----------------------------------------------------------------------------
  445. !   ...and that's all: the "gloves" code is self-contained.
  446. !
  447. !   Exercise for the reader: hide a (sharp) jewel inside the left glove.
  448. !     (Alter the glove class to make them containers open only when not worn.
  449. !      Add two "after" rules to warn the player if there's something sharp
  450. !      to the touch, one for putting on the pair of gloves, one for putting on
  451. !      an individual glove.)
  452. ! ----------------------------------------------------------------------------
  453.  
  454.  
  455. ! ----------------------------------------------------------------------------
  456. ! >CO  A traditional Inform example object:
  457. ! ----------------------------------------------------------------------------
  458.  
  459. Object -> cone "green cone"
  460.   with name "green" "cone" "emerald" "marzipan",
  461.        describe
  462.        [; if (cone has moved)
  463.               "^A misshapen cone of green marzipan sits here.";
  464.           "^Nearby is an emerald green cone, one foot high.";
  465.        ],
  466.        description "The cone seems to be made of emerald-coloured 
  467.                     marzipan.",
  468.        before
  469.        [; Eat: if (random(100) <= 30)
  470.                {   deadflag = 1;
  471.                    "Unfortunately, you seem to be allergic to almonds.";
  472.                }
  473.                "You nibble at a corner of the cone.";
  474.        ],
  475.        after
  476.        [; Take: "Taken. (Your hands are smeared with marzipan.)";
  477.           Drop: cone.description = "The cone is a vague green mess.";
  478.                 "The cone drops to the floor and sags a little.";
  479.        ],
  480.   has  edible;
  481.  
  482. ! ----------------------------------------------------------------------------
  483. ! >HW  It's the draught from this slightly-concealed window which propels the
  484. !      balloon:
  485. ! ----------------------------------------------------------------------------
  486.  
  487. Object -> "high window"
  488.   with name "high" "window",
  489.        description
  490.        [;  print "A narrow, high window ";
  491.            if (self has open) "through which a draught blows.";
  492.            "which is closed.";
  493.        ],
  494.        after
  495.        [; Open: StartDaemon(balloon);
  496.           Close: Achieved(2); StopDaemon(balloon);
  497.        ],
  498.   has  scenery openable open;
  499.  
  500. ! ----------------------------------------------------------------------------
  501. ! >BC  A typical locked container, containing a rather pathetic prize...
  502. ! ----------------------------------------------------------------------------
  503.  
  504. Object -> "bolted cupboard"
  505.   with name "bolted" "cupboard",
  506.        describe
  507.        [; if (self hasnt open) "^A shut cupboard is bolted to one wall.";
  508.           "^Bolted up on one wall is an open cupboard.";
  509.        ],
  510.        with_key key
  511.   has  locked container openable lockable static;
  512.  
  513. Object -> -> "boiled sweet"
  514.   with name "boiled" "sweet",
  515.        after
  516.        [; Eat: Achieved(0);
  517.                "It takes an irritatingly long time to eat.";
  518.        ],
  519.   has  edible;
  520.  
  521. ! ----------------------------------------------------------------------------
  522. ! >GB  This is really to demonstrate "transparent".  Shutting up the glowing
  523. ! >SB  ball in the glass box does not make the room go dark: shutting it up
  524. !      in the steel box does.  Also, you can examine things in the glass box
  525. !   even when the glass box is shut.
  526. !   (Note also that the Dark Room is explicitly told not to have "light",
  527. !   which it would otherwise inherit from the "Toyroom" class.)
  528. ! ----------------------------------------------------------------------------
  529.  
  530. Toyroom DarkRoom "Dark Room"
  531.   with description "A featureless storage room, hardly worth illumination.",
  532.        cant_go "The only exit is back south.",
  533.        s_to East_End
  534.   has  ~light;
  535.  
  536. Object -> "glass box with a lid"
  537.   with name "glass" "box" "with" "lid"
  538.   has  container transparent openable open;
  539.  
  540. Object -> "steel box with a lid"
  541.   with name "steel" "box" "with" "lid"
  542.   has  container openable open;
  543.  
  544.  
  545. Toyroom West_End "West End"
  546.   with name "soldiers" "model" "aircraft" "planes",
  547.        description
  548.           "The western end of the toyshop is blue, and soldiers and 
  549.            model aircraft line the shelves. A small office lies to 
  550.            the south.",
  551.        e_to Toyshop, s_to Office;
  552.  
  553. ! ----------------------------------------------------------------------------
  554. ! >BL  The class Block provides for stackable building blocks.
  555. !
  556. !   Note that with the "describe" routine missing, the game would still
  557. !   correctly describe stacks of blocks: just a little less elegantly.
  558. ! ----------------------------------------------------------------------------
  559.  
  560. Class  Block
  561.   with description "Just a child's building block, four inches on a side.",
  562.  
  563.        !   The parse_name routine below ensures that "take blocks"
  564.        !   works correctly:
  565.  
  566.        parse_name
  567.        [ i j;
  568.          for (::)
  569.          {   j=NextWord();
  570.              if (j=='block' or 'cube' or 'building' or (self.name)) i++;
  571.              else
  572.              {   if (j=='blocks' or 'cubes')
  573.                  {   parser_action=##PluralFound; i++; }
  574.                  else return i;
  575.              }
  576.          }
  577.        ],
  578.  
  579.        describe
  580.        [ c d e;
  581.            d = child(self);
  582.            while (d~=0 && d ofclass Block)
  583.            {   c++; e=d; d=child(d); }
  584.            if (c==0) rfalse;
  585.            print "^There is a pile of building blocks here, ";
  586.            while (c>=0)
  587.            {   print (address) e.name;  ! Sneaky: print the "name" out
  588.                if (c>0) print " on ";   ! using its dictionary address
  589.                c--; e=parent(e);
  590.            }
  591.            ".";
  592.        ],
  593.        before
  594.        [ c;
  595.          PutOn:
  596.            if (second ofclass Block)
  597.            {   if (child(second)~=0 && child(second) ofclass Block)
  598.                    "There's no room on the top of one cube for two more, side 
  599.                     by side.";
  600.            }
  601.            else
  602.                print "(They're really intended 
  603.                       to be piled on top of each other.)^";
  604.            c=second; while (c ofclass Block) c=parent(c);
  605.            if (c~=location or mantelpiece) "Too unsteady a base.";
  606.        ],
  607.        after
  608.        [ c stack;
  609.          PutOn:
  610.            stack=noun;
  611.            while (parent(stack) ofclass Block) { stack=parent(stack); c++; }
  612.            if (c<2)
  613.            {   if (Chris has general) rtrue;
  614.                rfalse;
  615.            }
  616.            if (c==2) "The pile of three cubes is unsteady, but viable.";
  617.            if (Chris has general)
  618.            {   Achieved(3);
  619.                "^Expertly he keeps the pile of four cubes stable.";
  620.            }
  621.            stack=noun;
  622.            while (parent(stack) ofclass Block)
  623.            {   c=stack; stack=parent(stack); move c to location; }
  624.            "The pile of four cubes wobbles, wobbles, steadies... and suddenly 
  625.             collapses!";
  626.          Take:
  627.            stack=child(noun); if (stack==0) rfalse;
  628.            while (stack~=0)
  629.            { c=stack; stack=child(stack); move c to location; }
  630.            "Your pile of cubes is collapsed as a result.";
  631.        ],
  632.   has  supporter;
  633.  
  634. Block -> "green cube"
  635.   with name "green";
  636. Block -> "red cube"
  637.   with name "red";
  638. Block -> "yellow cube"
  639.   with name "yellow";
  640. Block -> "blue cube"
  641.   with name "blue";
  642.  
  643. ! ----------------------------------------------------------------------------
  644. ! >CH  A guest appearance by my cousin Christopher, aged six (*), who plays
  645. !      with one thing at a time (easily forgetting which). Being "transparent"
  646. !      (no reflection on him!) means the parser allows the player to examine
  647. !      whatever he's playing with... but not to take it from him.
  648. !      (* In 1993, when this game was first written.)
  649. ! ----------------------------------------------------------------------------
  650.  
  651. Object -> Chris "Christopher"
  652.   with name "child" "boy" "chris" "christopher",
  653.        describe
  654.        [;  print "^A boy called Christopher sits here";
  655.            if (child(Chris) ~= nothing)
  656.                print ", playing with ", (a) child(Chris);
  657.            ".";
  658.        ],
  659.        life
  660.        [ x;
  661.            Ask:
  662.               switch(second)
  663.               {   'juggling', 'fluorescent', 'ball': "~That's mine!~";
  664.                   'helium', 'balloon': "Christopher yawns.";
  665.                   'cube', 'cubes': "~Bet I can make a higher tower than you.~";
  666.                   'toys', 'toyshop': "~Isn't it fabulous here?~";
  667.                   default: "~Dunno.~";
  668.               }
  669.            Answer:
  670.               switch(noun)
  671.               {   'hello', 'hallo', 'hi':
  672.                        "~Hello,~ says Christopher cheerfully.";
  673.                   default: "Christopher seems preoccupied.";
  674.               }
  675.            Attack: remove self;
  676.              "Christopher makes a run for it, effortlessly slipping past you!";
  677.            Kiss: "~That's soppy, that is.~";
  678.            Give:
  679.              if (noun==balloon) "He's too bored by the balloon.";
  680.              x=child(Chris);
  681.              if (x~=0)
  682.              {   move x to location;
  683.                  print "He forgets about ", (the) x, " and ";
  684.              }
  685.              else print "He ";
  686.              print "eagerly grabs ", (the) noun; move noun to Chris; ".";
  687.        ],
  688.        orders
  689.        [;  Drop: if (noun in Chris) "~Won't!  It's mine!~";
  690.            Take: "Christopher can't be bothered.";
  691.            Give: if (second==player) "~Get your own!~";
  692.            Go: "~But I like it here!~";
  693.            PutOn: if (noun notin Chris) "He is mightily confused.";
  694.                  if (~~(noun ofclass Block && second ofclass Block))
  695.                      "He can't see the point of this.";
  696.                  print "Christopher leans over with great concentration 
  697.                      and does so.^";
  698.                  move noun to player; give self general;
  699.                  <PutOn noun second>;
  700.                  give self ~general; rtrue;
  701.        ],
  702.        each_turn
  703.        [;  if (random(3)~=1) rtrue;
  704.            print "^Christopher ";
  705.            switch(random(4))
  706.            {  1: "yawns.";     2: "frowns.";
  707.               3: "stretches."; 4: "hums tonelessly.";
  708.            }
  709.        ],
  710.   has  animate proper transparent;
  711.  
  712. Object "fluorescent juggling ball" Chris
  713.   with initial "On the floor is a fluorescent juggling ball!",
  714.        name "fluorescent" "juggling" "ball",
  715.        description "It glows with soft light."
  716.   has  light;
  717.  
  718. ! ----------------------------------------------------------------------------
  719. ! >OF  A simple movement rule.
  720. ! ----------------------------------------------------------------------------
  721.  
  722. Toyroom Office "Office"
  723.   with description
  724.           "A small, grey office, with a broad stone mantelpiece. 
  725.            In the east wall is a doorway marked ~Exit~, and the Toyshop, 
  726.            of course, lies north.",
  727.        cant_go "The Toyshop floor lies north.",
  728.        n_to West_End,
  729.        e_to
  730.        [; if (score~=MAX_SCORE)
  731.               "A gong sounds. ~You cannot leave the Toyshop until 
  732.                you have done six interesting things!~";
  733.           deadflag=2;
  734.           "A gong sounds. ~Congratulations!  You may now leave the Toyshop 
  735.            and begin writing your own Inform game!~";
  736.        ];
  737.  
  738. ! ----------------------------------------------------------------------------
  739. ! >TB  A somewhat acquisitive container... but it can be taught to behave.
  740. ! ----------------------------------------------------------------------------
  741.  
  742. Object -> "toothed bag"
  743.   with name "toothed" "bag",
  744.        initial "In one corner is a curious, toothed bag.",
  745.        description "A capacious bag with a toothed mouth.",
  746.        before
  747.        [; LetGo: "The bag defiantly bites itself 
  748.                   shut on your hand until you desist.";
  749.        ],
  750.        after
  751.        [; Receive:
  752.               if (noun==cone)
  753.               {   self.before=0; self.after=0;
  754.                   "The bag wriggles interminably as it tries 
  755.                    to eat the enormous mass of marzipan. That'll 
  756.                    teach it.";
  757.               }
  758.               "The bag wriggles hideously as it swallows ", (the) noun, ".";
  759.        ],
  760.   has  container open;
  761.  
  762. ! ----------------------------------------------------------------------------
  763. ! >SL  Which can be put on the mantelpiece: the first time this is done, the
  764. !      game randomly decides which end is higher, and sticks to this decision.
  765. ! ----------------------------------------------------------------------------
  766.  
  767. Object -> -> spirit_level "spirit level"
  768.   with name "spirit" "level" "wood" "flask",
  769.        number 0,
  770.        description "A length of wood containing a flask of viscous 
  771.            green liquid, in which a bubble is trapped.",
  772.        before
  773.        [; Examine:
  774.           if (spirit_level in mantelpiece)
  775.           {   print "The bubble is at the ";
  776.               if (self.number==1) "northeast end.";
  777.               "southeast end.";
  778.           } 
  779.        ],
  780.        after
  781.        [; PutOn: if (second~=mantelpiece) rfalse;
  782.            if (spirit_level hasnt general) self.number=random(2);
  783.            give spirit_level general; Achieved(4);
  784.            print "You put the spirit level on the mantelpiece, 
  785.                   and the bubble slowly drifts towards the ";
  786.            if (self.number==1) "northeast.";
  787.            "southwest.";
  788.        ];
  789.  
  790. Object -> mantelpiece "mantelpiece"
  791.   with name "mantel" "mantle" "piece" "mantelpiece"
  792.   has  scenery supporter;
  793.  
  794. Object -> -> key "iron key"
  795.   with name "iron" "key", article "an";
  796.  
  797. ! ----------------------------------------------------------------------------
  798. ! >BB  A blackboard which can be written on or wiped clear.
  799. ! ----------------------------------------------------------------------------
  800.  
  801. Object -> -> chalk "stick of chalk"
  802.   with name "stick" "of" "chalk";
  803.  
  804. Array boardtext string 64;
  805.  
  806. Object -> blackboard "blackboard"
  807.   with name "board" "blackboard" "black",
  808.        describe
  809.        [;  <<Examine self>>; ],
  810.        before
  811.        [ i f;
  812.            Examine:
  813.                for (i=1:i<=boardtext->0:i++)
  814.                    if (boardtext->i~=' ' or 0) f=1;
  815.                if (f==0)
  816.                {   print "^The office blackboard is wiped clean.^";
  817.                    if (self hasnt general)
  818.                    {   give self general;
  819.                        "^[To write on it, try   > write ~message...~]";
  820.                    }
  821.                    rtrue;
  822.                }
  823.                print "^The office blackboard bears the message:^    ";
  824.                for (i=1:i<=boardtext->0:i++)
  825.                {   f=boardtext->i;
  826.                    if (f~=0) print (char) f;
  827.                }
  828.                new_line; rtrue;
  829.            Rub: for (i=1:i<=boardtext->0:i++) boardtext->i = ' ';
  830.                   "You wipe the blackboard clean.";
  831.        ],
  832.   has  static;
  833.  
  834. Global from_char; Global to_char;
  835. [ QuotedText i j f;
  836.    i = WordAddress(wn++); i=i-buffer;
  837.    if (buffer->i=='"')
  838.    {   for (j=i+1:j<=(buffer->1)+1:j++)
  839.            if (buffer->j=='"') f=j;
  840.        if (f==0) return -1;
  841.        from_char = i+1; to_char=f-1;
  842.        if (from_char>to_char) return -1;
  843.        while (buffer+f > WordAddress(wn)) wn++; wn++;
  844.        return 1;
  845.    }
  846.    return -1;
  847. ];
  848.  
  849. [ WriteSub i j;
  850.    if (chalk notin player) "You're holding nothing to write with.";
  851.    if (blackboard notin location) "The blackboard is elsewhere.";
  852.    for (i=from_char,j=1:i<=to_char && j<boardtext->0:i++,j++)
  853.        boardtext->j = buffer->i;
  854.    for (:j<boardtext->0:j++) boardtext->j=0;
  855.    Achieved(5);
  856.    <<Examine blackboard>>;
  857. ];
  858.  
  859. ! ----------------------------------------------------------------------------
  860. !   End of object definitions.
  861. ! ----------------------------------------------------------------------------
  862. !
  863. !   Routines and Entry Points
  864. !
  865. !   (Fuller examples of which can be found in the "Advent" example game.)
  866. !
  867. !   Initialise() just sets up the initial state of the game.
  868. !   We are required to set "location" to the start location of the
  869. !   player; the rest is optional.
  870. !
  871. !   StartDaemon(balloon)  starts the process which blows the balloon back
  872. !   and forth.
  873. ! ----------------------------------------------------------------------------
  874.  
  875. [ Initialise;
  876.   location=chair;  move satchel to player;
  877.  
  878.   print "^^^^^~What's so special about Inform,~ is the last thing you 
  879.          remember saying to the mad alchemist. Big mistake...^^";
  880.  
  881.   StartDaemon(balloon);
  882. ];
  883.  
  884. ! ----------------------------------------------------------------------------
  885. !   Print names of tasks out (when the library asks us to).  Note that they
  886. !   are numbered from 0 to NUMBER_TASKS-1.
  887. ! ----------------------------------------------------------------------------
  888.  
  889. [ PrintTaskName achievement;
  890.   switch(achievement)
  891.   {   0: "eating a sweet";
  892.       1: "driving the car";
  893.       2: "shutting out the draught";
  894.       3: "building a tower of four";
  895.       4: "seeing which way the mantelpiece leans";
  896.       5: "writing on the blackboard";
  897.   }
  898. ];
  899.  
  900. [ PrintRank;
  901.   print ", earning you the rank of ";
  902.   if (score >= 6)  "Toyshop manager.";
  903.   if (score >= 5)  "management trainee.";
  904.   if (score >= 4)  "undergraduate.";
  905.   if (score >= 3)  "schoolchild.";
  906.   if (score >= 2)  "nursery-school child.";
  907.   if (score >= 1)  "toddler.";
  908.   "newborn baby.";
  909. ];
  910.  
  911. ! ----------------------------------------------------------------------------
  912. !   Now (as promised earlier) we provide the replacement for BurnSub,
  913. !   specially adapted to the rules of the Toyshop:
  914. ! ----------------------------------------------------------------------------
  915.  
  916. [ BurnSub;
  917.     if (match hasnt light) "You have no source of flame.";
  918.     if (noun has animate) <<Attack noun>>;
  919.     if (noun==padded_floor)
  920.     {   deadflag=1;
  921.         "A gong sounds, but before a sepulchral voice finishes clearing 
  922.          its throat, the whole padded floor goes up in an inferno.";
  923.     }
  924.     "A gong sounds, and a sepulchral, rather disappointed voice says: 
  925.      ~It is forbidden to play with fire in the Toyshop.~";
  926. ];
  927.  
  928. ! ----------------------------------------------------------------------------
  929. !   And we provide one new action, "Burst", which in fact just passes over to
  930. !   "Attack", plus one for writing on the board:
  931. ! ----------------------------------------------------------------------------
  932.  
  933. [ BurstSub; <<Attack noun>>; ];
  934.  
  935. Include "Grammar";
  936.  
  937. Verb "burst" "pop" "prick" "stab" "pierce"
  938.                 * noun                           -> Burst;
  939.  
  940. Verb "write"    * QuotedText -> Write;
  941.  
  942. ! ----------------------------------------------------------------------------
  943.